from string import zfill
import socket


str_start 	= "["
str_end 	= "]"
int_no_size	= 4

PARENT_CLIENT = 0;
PARENT_SERVER = 1;


def encode_server_packet(str_type, tup_params):
	if str_type == 'ares':		
		# SERVER authentication resul packet
		bool_ok, str_result = tup_params
		int_length = len(str_result)+3
		# generate the header
		str_header = str_type + zfill(int_length, int_no_size)
		# generate the data
		if bool_ok:
			str_data = "ACK" + str_result
		else:
			str_data = "NAK" + str_result
	elif str_type == 'pxml':
		str_header 	= str_type + zfill(len(tup_params), int_no_size)
		str_data 	= tup_params
	elif str_type == 'psno':
		str_header 	= str_type + zfill(int_no_size, int_no_size)
		str_data 	= zfill(tup_params, int_no_size)
	elif str_type == 'mesg':
		str_header 	= str_type + zfill(len(tup_params), int_no_size)
		str_data 	= tup_params
	else:
		str_header	= None
		str_data	= None
	
	if str_header:
		return (str_start+str_header+str_data+str_end)
	else:
		return None


def encode_client_packet(str_type, tup_params):
	if str_type == 'auth':		
		# CLIENT autentication packet
		str_name, str_pass=tup_params
		int_length = len(str_name)+len(str_pass)+2*int_no_size
		# generate the header
		str_header = str_type + zfill(int_length, int_no_size)
		# generate the data
		str_data = zfill(len(str_name),int_no_size) + str_name + zfill(len(str_pass),int_no_size) + str_pass
	elif str_type == 'mesg':
		str_header 	= str_type + zfill(len(tup_params), int_no_size)
		str_data 	= tup_params
	else:
		str_header	= None
		str_data	= None	
	
	if str_header:
		return (str_start+str_header+str_data+str_end)
	else:
		return None


def receive_packet(sock_remote, bool_is_server, verbose = True):
	try:	
		data = sock_remote.recv(len(str_start))
		#if a packet begins
		if len(data) == len(str_start):
			if data == str_start:
				if verbose: print " packet preheader successfuly received "
				# get header
				data = sock_remote.recv(2*int_no_size)
				if len(data) == 2*int_no_size:
					str_type 	= data[0:4]
					int_length 	= int(data[4:8])
					int_extracted	= 0
					str_data	= "" 
					# extract the data
					retries = int(int_length/1400.)+2
					if verbose: print " packet header received. type=",str_type,"length=",int_length

					while retries>0 and int_extracted<int_length:
						str_current = sock_remote.recv(int_length-int_extracted)
						retries = retries - 1
						int_extracted = int_extracted + len(str_current)
						str_data = str_data + str_current
						if verbose: print " packet data received:", int_extracted,"of", int_length

					data = str_data

					if len(data) == int_length:
						str_data = data
						# receive the end of the packet
						data = sock_remote.recv(len(str_end))
						if (len(data) == len(str_end)) and (data == str_end):
							if verbose: print "packet footer successfuly received. Parsing..."
							# successfuly received packet
							return (str_type, str_data)
							
			# invalid packet
			return None
		elif len(data) == 0:
			# connection close packet
			if bool_is_server:
				return ('internal-error', "Connection closed")
			else:
				return ('ares',"NAKServer connection was lost. Check your Internet connection.")
		else:
			# invalid packet
			return None
	except socket.error, arg:
		# socket error
		if bool_is_server:
			return ('internal-error', "Connection error")
		else:
			return ('ares',"NAKServer connection was lost. Check your Internet connection.")
	except ValueError:
		# value errors => invalid packet
		return None
	
	
def decode_client_packet(tup_packet):
	try:
		str_type, str_data = tup_packet	
		
		if str_type == 'ares':
			# authentication result packet
			str_result  = str_data[0:3]
			str_message = str_data[3:]
			if str_result == 'ACK':
				bool_accepted = True
			else:
				bool_accepted = False
			return (str_type, (bool_accepted, str_message))
			
		elif str_type == 'pxml':
			# presentation xml  packet
			return tup_packet
			
		elif str_type == 'psno':
			# presentation slide no packet
			str_result  = str_data[0:int_no_size]
			int_slide 	= int(str_result)
			return (str_type, int_slide)
			
		if str_type == 'mesg':
			return tup_packet
		else:
			return None
		
	except ValueError:
		return None


def decode_server_packet(tup_packet):
	try:
		str_type, str_data = tup_packet	
		
		if str_type == 'auth':
			# authentication packet
			str_no1 	= str_data[0:int_no_size]
			int_no1		= int (str_no1)
			if int_no1+int_no_size >= len(str_data):
				return None # invalid packet
			
			str_no2 	= str_data[int_no_size+int_no1: 2*int_no_size+int_no1]
			int_no2		= int(str_no2)
			
			if int_no1+int_no2+2*int_no_size != len(str_data):
				return None # invalid packet
			
			str_user	= str_data[int_no_size:int_no_size+int_no1]
			str_pass	= str_data[int_no1+2*int_no_size:]
			
			return (str_type, (str_user, str_pass))
			
		if str_type == 'mesg':
			return tup_packet
			
			return (str_type, (str_user, str_pass))
		elif str_type == 'internal-error':
			return tup_packet			
		else:
			return None
		
	except ValueError:
		return None
	
